#!/usr/bin/env python
#!-*-coding:utf-8 -*-

from diagExcept import DiagArgsTypeExept
import binascii

#press key
SCI_VK_0 = '30 00 00 00'  #'0'
SCI_VK_1 = '31 00 00 00'
SCI_VK_2 = '32 00 00 00'
SCI_VK_3 = '33 00 00 00'
SCI_VK_4 = '34 00 00 00'
SCI_VK_5 = '35 00 00 00'
SCI_VK_6 = '36 00 00 00'
SCI_VK_7 = '37 00 00 00'
SCI_VK_8 = '38 00 00 00'
SCI_VK_9 = '39 00 00 00' #'9'
SCI_VK_STAR = '2A 00 00 00'  #'*'
SCI_VK_POUND = '23 00 00 00' #'#'
SCI_VK_CALL = '01 00 00 00'   #0x01
# If a key is used as both SCI_VK_POWER and SCI_VK_CANCEL, only use SCI_VK_POWER
SCI_VK_POWER = '02 00 00 00' #0x02
SCI_VK_CANCEL = '03 00 00 00' #0x03
SCI_VK_UP = '04 00 00 00' #0x04
SCI_VK_DOWN = '05 00 00 00' #0x05
SCI_VK_LEFT = '06 00 00 00' #0x06
SCI_VK_RIGHT = '07 00 00 00' #0x07
SCI_VK_MENU_SELECT = '08 00 00 00' #0x08
SCI_VK_MENU_CANCEL = '09 00 00 00' #0x09
SCI_VK_SIDE_UP = '0A 00 00 00' #0x0A
SCI_VK_SIDE_DOWN = '0B 00 00 00' #0x0B
SCI_VK_OK = '0C 00 00 00' #0x0C
SCI_VK_WEB = '0D 00 00 00' #0x0D
SCI_VK_CAMERA = '0E 00 00 00' #0x0E

#cmd
DIAG_SOFTKEY_F = '01'   #键盘主命令
DIAG_AT_F = '68'       #AT主命令
DIAG_POWER_F = "07"  #功能机power主命令

DIAG_SOFTKEY_FLAG = 1
DIAG_AT_FLAG = 2
DIAG_POWER_FLAG = 3


#sub cmd
DIAG_NORMAL_KEY_MSG_INFO_F = '00'  #键盘子命令 down and up
DIAG_KEY_MSG_DOWN_INFO_F = '01'    #down
DIAG_KEY_MSG_UP_INFO_F = '02'      #up
DIAG_POWER_OFF_F = '01'    #power off
DIAG_POWER_ON_F = '00'     #power on

DIAG_HEADER_LENGTH = 8  #DIAG协议头长度为8

PRESSKEY = {
    '0': SCI_VK_0, '1': SCI_VK_1, "2": SCI_VK_2, "3": SCI_VK_3, "4": SCI_VK_4, "5": SCI_VK_5,
    '6': SCI_VK_6, '7': SCI_VK_7, "8": SCI_VK_8, "9": SCI_VK_9, "*": SCI_VK_STAR, "#": SCI_VK_POUND,
    'CALL': SCI_VK_CALL, 'POWER': SCI_VK_POWER, "CANCEL": SCI_VK_CANCEL, "UP": SCI_VK_UP,
    'DOWN': SCI_VK_DOWN, 'LEFT': SCI_VK_LEFT, 'RIGHT': SCI_VK_RIGHT, 'MENU_SELECT': SCI_VK_MENU_SELECT,
    'MENU_CANCEL': SCI_VK_MENU_CANCEL, "SIDE_UP": SCI_VK_SIDE_UP, "SIDE_DOWN": SCI_VK_SIDE_DOWN,
    "OK": SCI_VK_OK, "WEB": SCI_VK_WEB, 'CAMERA': SCI_VK_CAMERA
}


class DiagCommand(object):
    def __init__(self):
        pass

    def __set_diag_SN(self):
        return '00 00 00 00'

    def __get_diag_leng(self, diag_data):
        """
        根据diag协议中数据区域的数据，返回一个十六进制的字符串，表示整个协议的长度
        :param diag_data:diag协议中数据区域的数据，String类型
        :return:String
        """
        if not isinstance(diag_data, (str, unicode)):
            raise DiagArgsTypeExept()

        diag_data_len = len(diag_data.replace(" ", ""))/2

        diag_len_str = str(hex(DIAG_HEADER_LENGTH+diag_data_len))[2:]

        len_str = ''
        if len(diag_len_str) == 1:
            len_str = "0"+diag_len_str + ' 00'
        elif len(diag_len_str) == 2:
            len_str = diag_len_str + ' 00'
        elif len(diag_len_str) == 3:
            len_1 = "0"+diag_len_str[0]
            len_2 = diag_len_str[1:]
            if int(len_1,16) > len(len_2):
                len_str = len_1 + " " + len_2
            else:
                len_str = len_2 + " " + len_1
        else:
            len_1 = diag_len_str[0:2]
            len_2 = diag_len_str[2:]
            if int(len_1, 16) > len(len_2):
                len_str = len_1 + " " + len_2
            else:
                len_str = len_2 + " " + len_1
        return len_str

    def __handle_special(self, one_frame):
        """
        处理数据帧中特殊的数值，0x7E，0x7D
        :param one_frame: 一帧数据
        :return:
        """
        # TODO, 对于数据帧中含有0x7D的需要转化
        new_one_frame = ""
        one_frame = one_frame.replace(" ", "")
        for x in xrange(2, len(one_frame)+2, 2):
            sp = one_frame[x - 2:x]
            if sp.upper() == "7E":
                new_one_frame += "7D5E"
            elif sp.upper() == "7D":
                new_one_frame += "7D5D"
            else:
                new_one_frame += sp
        return new_one_frame

    def __assembly_diag(self, cmd, diag_cmd_type=None, perss_type="normal"):
        """
        组装diag命令
        :param cmd: 十六进制的字符串
        :param diag_cmd_type: diag协议的类型，是AT命令还是按键命令
        :return:
        """
        diag_sn = "00 00 00 00"
        diag_length = self.__get_diag_leng(cmd)
        if diag_cmd_type == DIAG_SOFTKEY_FLAG:
            diag_cmd = DIAG_SOFTKEY_F
            if perss_type == 'normal':
                diag_sub_cmd = DIAG_NORMAL_KEY_MSG_INFO_F
            elif perss_type == 'up':
                diag_sub_cmd = DIAG_KEY_MSG_UP_INFO_F
            else:
                diag_sub_cmd = DIAG_KEY_MSG_DOWN_INFO_F
        elif diag_cmd_type == DIAG_AT_FLAG:
            diag_cmd = DIAG_AT_F
            diag_sub_cmd = DIAG_NORMAL_KEY_MSG_INFO_F
        elif diag_cmd_type == DIAG_POWER_FLAG:
            diag_cmd = DIAG_POWER_F
            if perss_type == 'off':
                diag_sub_cmd = DIAG_POWER_OFF_F
            elif perss_type == 'on':
                diag_sub_cmd = DIAG_POWER_ON_F
        else:
            raise Exception("diag_cmd_type({}) is error!".format(diag_cmd_type))
        #TODO   1、协议的构造；2、7E的校验

        diag_data = (diag_sn+ diag_length + diag_cmd + diag_sub_cmd + cmd).replace(" ", "")
        diag_ = self.__handle_special(diag_data)

        return binascii.unhexlify(diag_)

    def getAtCommand(self, AtCmd):
        """
        1、该函数对外提供
        2、参数为AtCmd的字符串
        3、返回一个diag协议的字符串，十六进制
        :param AtCmd:
        :return:
        """
        if not isinstance(AtCmd, (str, unicode)):
            raise Exception("AtCmd of getAtCommand function must is string!")

        atCmdHex = binascii.hexlify(AtCmd)
        return self.__assembly_diag(atCmdHex, diag_cmd_type=DIAG_AT_FLAG)

    def getpresskeycommand(self, pressKey, perssType="normal"):
        """

        :param pressKey: 按键名称
        :param perss_type: 按键动作类型
        :return:
        """
        if not self.check_input_press_key(pressKey):
            raise Exception("pressKey({}) is error!".format(pressKey))

        pressValue = PRESSKEY.get(pressKey.upper())
        signalCode = '01 A0'
        size = '08 00'
        cmd = signalCode + size + pressValue
        return self.__assembly_diag(cmd, diag_cmd_type=DIAG_SOFTKEY_FLAG, perss_type=perssType)

    def getrebootcommand(self, type_power="off"):
        """

        :param type_power:
        :return:
        """
        return self.__assembly_diag("", diag_cmd_type=DIAG_POWER_FLAG, perss_type=type_power)

    def check_input_press_key(self, press_key):
        """
        校验输入的按键是否正确
        :param press_key:
        :return: True/False
        """
        if not isinstance(press_key, (str, unicode)):
            raise Exception("press_key of check_input_press_key function must is string!")

        if press_key.upper().strip() in PRESSKEY.keys():
            return True

        return False

    def getTpCommand(self):
        return binascii.unhexlify("7E 00 00 00 00 10 00 22 00 01 00 64 00 14 00 14 00 7E".replace(" ",""))